local skynet = require "skynet"
local Module = require "core.Module"
local PlayerProto = require "modules.player.PlayerProto"
local SkynetQueue = require "skynet.queue"
local protoQueue = SkynetQueue()
local Services = require "global.Services"
local Const = require "enum.Const"
---@type PlayerMgr
local PlayerMgr = Services.PLAYER_MGR

local M = {}

local gate
local handlers = {}
local players = {}
local fd2player = {}

---@type table<PlayerId, SkynetQueue>
local playerQueues = {}

function M.close(fd, code)
    if not fd2player[fd] then
        return
    end

    local player = fd2player[fd]
    fd2player[fd] = nil
    if player.id and code ~= Const.CONNECT_CLOSE_CODE.NORMAL then
        PlayerMgr:logout(player.id)
    end

    players[player.id] = nil
    playerQueues[fd] = nil
end

function M.handle(fd, protoId, protoName, data)
    local player = fd2player[fd]
    GLOGF("receive proto from fd: %d, player: %s, protoId: 0x%04x, protoName: %s, data: %s", fd, player and player.id,
        protoId, protoName, table.dump(data))
    if not player.id and protoId ~= PlayerProto.LOGIN then
        GLERRF("first proto: 0x%04x is not login, data: %s", protoId, table.dump(data))
        return
    end

    -- 消息处理
    local handler = handlers[protoName]
    assert(handler, "unknown command, cmd: " .. tostring(protoName))
    local playerQueue = playerQueues[fd] or SkynetQueue()
    local retProtoId, retData = playerQueue(handler, fd2player[fd], data)
    if retProtoId == nil then -- 有返回值
        return
    end

    -- 如果协议第一个返回值不是协议id(一个数字)，那么这个协议应该是个对称协议，其返回的协议id就是请求过来的协议id
    if type(retProtoId) ~= "number" then
        retData = retProtoId
        retProtoId = protoId
    end

    skynet.send(gate, "send", fd, protoId, retData)
end

function M.accept(fd, addr)
    local player = {
        fd = fd,
        addr = addr,
        gate = gate
    }

    players[fd] = player
end

function M.start(conf)
    gate = conf.gate
end

local function initHandler(mod)
    -- 初始化协议处理器
    local ok, modHandler = pcall(require, Module.handlerPath(mod, true))
    if not ok then
        -- 没有协议处理器
        return
    end

    for protoName, func in pairs(modHandler) do
        assert(not handlers[protoName], "duplicate proto key: " .. protoName)
        handlers[protoName] = func
    end
end

function M.init()
    skynet.dispatch_lua(M)

    table.foreach(Module.allHandlerMod(), initHandler)
end

return M
